﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Xml;
using System.Configuration;

namespace ServidorDeGestionDeClientes
{
    public class ClientServer
    {
        static List<Cliente> ListaClientes;
        static CommQueueManager QueueMgr;
        static PayQueueManager PayQueueMgr;

        public ClientServer()
        {
            ListaClientes = new List<Cliente>();
            QueueMgr = new CommQueueManager();
            PayQueueMgr = new PayQueueManager();
            lock (ListaClientes)
            {
                CargarClientes();
            }
            Thread ThreadQueue = new Thread(ReceiveMessage);
            ThreadQueue.Start();
            Thread ThreadPayQueue = new Thread(ReceivePay);
            ThreadPayQueue.Start();
        }

        private void CargarClientes()
        {
            XmlDocument inventory = new XmlDocument();
            string path = ConfigurationManager.AppSettings["XmlPath"];
            inventory.Load(path);

            XmlNodeList elements = inventory.SelectNodes("//Clientes//Cliente");        

            foreach (XmlElement element in elements)
            {
                Cliente c = new Cliente();
                int id = Int32.Parse(element.GetAttribute("id"));

                c.Nombre = element.GetAttribute("nombre");
                c.Identificador = id;
                c.Saldo = Int32.Parse(element.GetAttribute("saldo"));
                c.TipoCliente = element.GetAttribute("tipoCliente");

                //XmlDocument cobros = new XmlDocument();
                //cobros.LoadXml(element.InnerXml);
                if (element.HasChildNodes)
                {
                    //XmlNodeList elementosCobro = cobros.SelectNodes("//Consumo");
                    XmlNodeList elementosCobro = element.ChildNodes;

                    foreach (XmlElement consumo in elementosCobro)
                    {
                        if (c.Consumos == null)
                            c.Consumos = new List<int>();
                        c.Consumos.Add(Int32.Parse(consumo.InnerText));
                    }
                }

                ListaClientes.Add(c);
            }
        }

        private void ReceiveMessage()
        {
            QueueMgr.ReceiveMessage();
        }

        private void ReceivePay() 
        {
            PayQueueMgr.ReceiveMessage();
        }

        public static bool ClienteExiste(int id)
        {
            bool Retorno = false;
            foreach (Cliente cliente in ListaClientes)
            {
                if (cliente.Identificador == id)
                {
                    Retorno = true;
                }
            }
            return Retorno;
        }

        public bool CrearCliente(int id, string nombre, int saldo, string tipo)
        {
            try
            {
                lock (ListaClientes)
                {
                    Cliente Nuevo = new Cliente(id, nombre, saldo, tipo);
                    ListaClientes.Add(Nuevo);
                    AgregarXml(Nuevo);
                }
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        private static void AgregarXml(Cliente Nuevo)
        {
            XmlDocument originalXml = new XmlDocument();
            string path = ConfigurationManager.AppSettings["XmlPath"];

            originalXml.Load(path);

            XmlNode menu = originalXml.SelectSingleNode("Clientes");

            XmlNode newSub = originalXml.CreateNode(XmlNodeType.Element, "Cliente", null);

            XmlAttribute xa = originalXml.CreateAttribute("nombre");
            xa.Value = Nuevo.Nombre;

            XmlAttribute xb = originalXml.CreateAttribute("id");
            xb.Value = Nuevo.Identificador.ToString();

            XmlAttribute xc = originalXml.CreateAttribute("saldo");
            xc.Value = Nuevo.Saldo.ToString();

            XmlAttribute xd = originalXml.CreateAttribute("tipoCliente");
            xd.Value = Nuevo.TipoCliente.ToString();
            
            newSub.Attributes.Append(xa);
            newSub.Attributes.Append(xb);
            newSub.Attributes.Append(xc);
            newSub.Attributes.Append(xd);

            if (Nuevo.Consumos != null)
            {
                foreach (var cobro in Nuevo.Consumos)
                {
                    XmlNode newChild = originalXml.CreateNode(XmlNodeType.Element, "Cobro", null);
                    newChild.InnerText = cobro.ToString();
                    newSub.AppendChild(newChild);

                }
            }
           menu.AppendChild(newSub);
            originalXml.Save(path);
                       
        }

        public static bool AgregarCobroCliente(int idCliente, int cobro) 
        {
            lock (ListaClientes)
            {
                var cli = ListaClientes.Where(p => p.Identificador == idCliente).FirstOrDefault();
                if (cli == null)
                    return false;

                cli.Consumos.Add(cobro);
                AgregarCobro(idCliente, cobro);                

            }
            return true;
        }
        public static bool AgregarSaldoCliente(int idCliente, int saldo) 
        {
            lock (ListaClientes) 
            {
               var cli = ListaClientes.Where(p => p.Identificador == idCliente).FirstOrDefault();
               if (cli == null)
                   return false;

               int saldoActual = cli.Saldo + saldo;
               cli.Saldo = saldoActual;
               AgregarSaldo(idCliente, saldo);

               if (saldoActual <= 0)
                   QueueMgr.SendMessageToQueue("C05", "Sin saldo");
               else if (saldoActual < saldo)
                   QueueMgr.SendMessageToQueue("C04", "Poco Saldo");


            }
            return true;

        }
        
        private static void AgregarSaldo(int idCliente, int saldo)
        {
            XmlDocument inventory = new XmlDocument();
            string path = ConfigurationManager.AppSettings["XmlPath"];
            inventory.Load(path);

            XmlNodeList elements = inventory.SelectNodes("//Clientes//Cliente");

            foreach (XmlElement element in elements)
            {
                int id = Int32.Parse(element.GetAttribute("id"));
                if (id == idCliente)
                {
                    int saldoActual = Int32.Parse(element.GetAttribute("saldo"));
                    saldoActual += saldo;
                    element.SetAttribute("saldo", saldoActual.ToString());
                   
                }
            }
            inventory.Save(path);
        }

        private static void AgregarCobro(int idCliente, int cobro)
        {
            XmlDocument inventory = new XmlDocument();
            string path = ConfigurationManager.AppSettings["XmlPath"];
            inventory.Load(path);

            XmlNodeList elements = inventory.SelectNodes("//Clientes//Cliente");
           
            foreach (XmlElement element in elements)
            {
                int id = Int32.Parse(element.GetAttribute("id"));
                if (id == idCliente)
                {
                    XmlNode newChild = inventory.CreateNode(XmlNodeType.Element, "Cobro", null);
                    newChild.InnerText = cobro.ToString();
                    element.AppendChild(newChild);
                    element.AppendChild(newChild);
                }
            }
            inventory.Save(path);
        }

        public int GetNuevoId()
        {
            return ListaClientes.Count + 1;
        }

        public static void AccionMensajes(string accion, string datos)
        {
            switch (accion)
            {
                case "C01": //Existe cliente
                    int IdCliente = Int32.Parse(datos.Split(';')[0]);
                    string IPAgente = datos.Split(';')[1];
                    bool Retorno = ClienteExiste(IdCliente);
                    string Label;
                    if (Retorno)
                        Label = "C02";
                    else
                        Label = "C03";
                    string Mensaje = IPAgente + ";" + IdCliente.ToString() + ";";
                    QueueMgr.SendMessageToQueue(Label, Mensaje);
                    break;

                case "C06":
                    int IdCliente_2 = Int32.Parse(datos.Split(';')[0]);
                    int Consumo = Int32.Parse(datos.Split(';')[1]);
                    
                    break;

                case "C07":
                    var data = datos.Split(';');
                    int IdCliente_07 = 0;
                    int consumo = 0;
                    Int32.TryParse(data[0],out IdCliente_07);
                    Int32.TryParse(data[1], out consumo);
                    AgregarCobroCliente(IdCliente_07, consumo);
                    break;

                case "C08" :
                    var data2 = datos.Split(';');
                    int IdCliente_08 = 0;
                    int precio = 0;
                    Int32.TryParse(data2[0],out IdCliente_08);
                    Int32.TryParse(data2[1], out precio);
                    AgregarSaldoCliente(IdCliente_08, -precio);
                    break;
            }
        }
    }
}
